#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;



/*
把 1∼n 这 n 个整数排成一行后随机打乱顺序，输出所有可能的次序。

输入格式
一个整数 n。

输出格式
按照从小到大的顺序输出所有方案，每行 1 个。
首先，同一行相邻两个数用一个空格隔开
其次，对于两个不同的行，对应下标的数一一比较，字典序较小的排在前面。
*/ 

const int N = 10;

int n;
int state[N];   // 0 表示还没放数，1~n表示放了哪个数
bool used[N];   // true表示用过，false表示还未用过

void dfs(int u)
{
    if (u > n)  // 边界
    {
        for (int i = 1; i <= n; i ++ ) printf("%d ", state[i]); // 打印方案
        puts("");

        return;
    }

    // 依次枚举每个分支，即当前位置可以填哪些数
    //初始填第一个数时可填1，2，3；填完第一个数后向下递归填第二三个数,递归完成之后要将数回复现场
    //函数递归调用时会将数据的状态存入到递归调用栈中,在函数返回时恢复现场
    for (int i = 1; i <= n; i ++ )
        if (!used[i])
        {
            state[u] = i;
            used[i] = true;
            dfs(u + 1); //递归搜索下一个位置

            // 恢复现场
            state[u] = 0;  //回溯
            used[i] = false;
        }
}

int main()
{
    scanf("%d", &n);

    dfs(1);//从第一个位置开始搜索遍历

    return 0;
}
